package com.ch.web.mq;

import com.ch.XiaoYuanWebApplication;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.stream.Collectors;

/**
 * 自定义mq类
 */
public class RabbitMqCustomTemplate implements BeanFactoryAware {


    private BeanFactory beanFactory;
    /**
     * 用来存储消息的
     */
    private final static BlockingQueue<MessageRegister> queue = new PriorityBlockingQueue<>(10);
    /**
     * 扫描包下的handler  String 是路由key  HandlerRabbitMq是handler 具体的实现类
     */
    private final static Map<String, HandlerRabbitMq> mqHandler = new ConcurrentHashMap<>();
    /**
     * 存储回调消息
     */
    private final static PriorityBlockingQueue<ResultMessage> CALL_QUEUE = new PriorityBlockingQueue<>();

    private  Thread thread;

    private Object mainApp;

    public void sendMsg() {
        thread= new Thread(() -> {
            while (true) {
                try {
                    MessageRegister take = queue.take();
                    String routKey = take.getRoutKey();
                    HandlerRabbitMq handlerRabbitMq = mqHandler.get(routKey);
                    if (ObjectUtils.isEmpty(handlerRabbitMq)) {
                        ResultMessage resultMessage = ResultMessage.failCreate(take, routKey + "不存在");
                        CALL_QUEUE.add(resultMessage);
                    } else {
                        handlerRabbitMq.receiveMsg(take);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.setDaemon(true);
        thread.start();
    }

    public void addMsg(MessageRegister messageRegister) throws InterruptedException {
        //收到消息 加入队列
        queue.put(messageRegister);
    }

    /**
     * 扫描自定义的 HandlerRabbitMq接口以及是否含有CutosListerMq注解
     *
     * @throws IOException
     */
    @PostConstruct
    public void initHandler() throws IOException {
        Package name = mainApp.getClass().getPackage();
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        //进行扫描 扫描实现了handlerRabbitMq的接口的类
        String name1 = name.getName();
        String replace = name1.replace('.', '/');
        Enumeration<URL> resources = loader.getResources(replace);
        List<File> dirs = new ArrayList<File>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            String decode = URLDecoder.decode(resource.getFile(), "utf-8");
            dirs.add(new File(decode.substring(1)));
        }
        List<String> mqClass = null;
        for (File dir : dirs) {
            mqClass = findMqClass(replace, dir);
        }
        if (mqClass != null) {
            doListCreateHandler(mqClass);
        }
        sendMsg();
    }

    private void doListCreateHandler(List<String> mqClass) {
        List<String> stringList = mqClass.stream().map(s -> s.replace("/", ".").substring(0, s.length() - 6)).collect(Collectors.toList());
        stringList.forEach(s -> {
            try {
                Class<?> aClass = Class.forName(s);
                if (aClass.isInterface() || aClass.isAnnotation()) {
                } else if (HandlerRabbitMq.class.isAssignableFrom(aClass)) {
                    //如果这个类是的 我们从spring框架中获取即可
                    Object bean = this.beanFactory.getBean(aClass);
                    //代表是我的rabbitmq的子类
                    Method[] methods = bean.getClass().getMethods();
                    for (Method method : methods) {
                        CutosListerMq annotation = method.getAnnotation(CutosListerMq.class);
                        if (annotation != null) {
                            mqHandler.putIfAbsent(annotation.value(), (HandlerRabbitMq) bean);
                        }
                    }
                }
            } catch (ClassNotFoundException ignored) {
            }
        });
    }


    public List<String> findMqClass(String packgeName, File file) {
        List<String> list = new ArrayList();
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                if (file1.isDirectory()) {
                    list.addAll(findMqClass(packgeName + "/" + file1.getName(), file1));
                } else if (file1.getName().lastIndexOf(".class") > 0) {
                    list.add(packgeName + "/" + file1.getName());
                }
            }
        } else if (file.getName().lastIndexOf(".class") > 0) {
            list.add(packgeName + "/" + file.getName());
        }
        return list;
    }

    /**
     * 写主类的运行类
     *
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.mainApp = beanFactory.getBean(XiaoYuanWebApplication.class);
        this.beanFactory = beanFactory;
    }

    public static PriorityBlockingQueue<MessageRegister> getQueue() {
        return (PriorityBlockingQueue<MessageRegister>) queue;
    }

    public static PriorityBlockingQueue<ResultMessage> getCallQueue() {
        return CALL_QUEUE;
    }
    public void destroy(){
        thread.interrupt();
    }
}
